/*
 * TTracer.cpp
 *
 *  Created on: 2010-12-15
 *      Author: Xairy
 */

#include "TTracer.h"
#include "RCallStack.h"
#include "Client.h"
#include "RLogSystem.h"

_LIT(KPanicServerInit, "PanicServer-Init");

TBool TTracer::iIsOn = EFalse;

#define KPanicThreadFull -1
#ifdef USE_MULTITHREAD_LLLLL
/**
 *  多线程支持代码
 * TODO: 这是一段不安全的代码，需要对全局变量的iThreadTracer进行操作加载读写锁
 */
TThreadClient TTracer::iThreadTracer[KMaxThreadNum];
TInt TTracer::iThreadNum = 0;

TThreadClient::~TThreadClient()
{
    if(iClient)
    {
        delete iClient;
        iClient = NULL;
    }
}

void TTracer::Init()
{
    RThread cThread;
    TThreadId id = cThread.Id();
    TFullName cThreadName = cThread.FullName();
    if(iThreadNum >= KMaxThreadNum)
    {
        User::Panic(KPanicServerInit, KPanicThreadFull);
    }
    
    iThreadTracer[iThreadNum].iThreadId = id.Id();
    TRAPD(err, iThreadTracer[iThreadNum].iClient = 
            CClient::InstanceL(cThreadName));
    if(KErrNone != err)
    {
        User::Panic(KPanicServerInit, err);
    }
    ++iThreadNum;
    iIsOn = ETrue;
}

void TTracer::Destory()
{
    RThread cThread;
    TUint64 id = cThread.Id().Id();
    TInt index = -1;
    for(index = 0; index < iThreadNum; ++index)
    {
        if(iThreadTracer[index].iThreadId == id)
            break;
    }
    if(index < iThreadNum)
    {
        delete iThreadTracer[index].iClient;
        iThreadTracer[index].iClient = NULL;
        
        for(TInt temp = index; temp < iThreadNum - 1; ++temp)
        {
            iThreadTracer[index].iThreadId = iThreadTracer[index + 1].iThreadId;
            iThreadTracer[index].iClient = iThreadTracer[index + 1].iClient;
        }
        --iThreadNum;
    }
}

void TTracer::MainThreadExit()
{
    for(TInt index = 0; index < iThreadNum; ++index)
    {
        __ASSERT_ALWAYS(iThreadTracer[index].iClient != NULL, User::Invariant());
        delete iThreadTracer[index].iClient;
        iThreadTracer[index].iClient = NULL;
    }
}

TThreadClient* TTracer::Find(TUint64 aThreadId)
{
    TInt index;
    for(index = 0; index < iThreadNum; ++index)
    {
        if(aThreadId == iThreadTracer[index].iThreadId)
            return &iThreadTracer[index];
    }
    return NULL;
}

TTracer::TTracer(const TText* aFunc)
    :iFunc(aFunc)
{
    RThread cThread;
    TUint64 id = cThread.Id().Id();
    
    iThreadClient = Find(id);
    if(iThreadClient != NULL)
    {
        iThreadClient->iClient->Stack().Push(TStringItemType, 
                            iFunc.Length() * sizeof(TUint16), iFunc.Ptr());
    }
}

TTracer::~TTracer()
{
    if (std::uncaught_exception()) 
    {
       iThreadClient->iClient->iSession.ClientLeave();
    }
    __ASSERT_ALWAYS(!iThreadClient->iClient->Stack().isEmpty(), User::Invariant());
    iThreadClient->iClient->Stack().Pop();
}


#else
CClient* TTracer::iTracer = NULL;
TFullName TTracer::iTracerName;

void TTracer::Init(TInt aStackSize)  
{
    RProcess cProcess;
    iTracerName = cProcess.FullName();
    TRAPD(err, iTracer = CClient::InstanceL(iTracerName, aStackSize));
    if(KErrNone != err)
    {
        User::Panic(_L("PanicServer-Init"), err);
    }
    __ASSERT_ALWAYS(iTracer != NULL && iTracer->Stack().IsAvaliable(), User::Invariant());
    iIsOn = ETrue;
}

void TTracer::Destory()
{
    CClient::CloseInstance(iTracerName);
    iTracerName.SetLength(0);
    iIsOn = EFalse;
}

TTracer::TTracer(const TText* aFunc)
    :iFunc(aFunc)
{
   if(iIsOn)
   {
       iTracer->Stack().Push(TStringItemType, 
           iFunc.Length() * sizeof(TUint16), iFunc.Ptr());
   }
}

TTracer::~TTracer()
{
    if(iIsOn)
    {
        if(std::uncaught_exception())
        {
            iTracer->iSession.ClientLeave();
        }
        __ASSERT_ALWAYS(!iTracer->Stack().isEmpty(), User::Invariant());
        iTracer->Stack().Pop();
    }
}

#endif




